<?php
/**
 * User:
 * Date:
 * Time:
 */

namespace App\Common\RedisCache;


abstract class AbstractSortedSetCache extends AbstractCache
{
    /**
     * 将一个或多个成员元素及其分数值加入到有序集当中，如果成员已存在则更新它的分数值，如果集合不存在则创建
     *
     * @param array $arr 元素（唯一）与其分数值（分数值可以是整数值或双精度浮点数）组成的数组
     *
     * @return int  返回添加成功的成员数量
     */
    public function set($arr)
    {
        $this->select();
        $num = 0;
        if ($arr && is_array($arr)) {
            foreach ($arr as $key => $value) {
                if (is_numeric($value)) {
                    $num += $this::$client->zadd($this->key, $value, $key);
                }
            }
        }
        return $num;
    }

    /**
     * @param $score
     * @param $value
     *
     * @return int
     */
    public function setOne($score, $value)
    {
        $this->select();
        $num = $this::$client->zadd($this->key, $score, $value);
        return $num;
    }

    /**
     * 返回有序集中，指定区间内的成员。默认返回所有成员(默认升序排列)
     *
     * @param int  $start      起始位置，从0开始计，默认0
     * @param int  $stop       结束位置，-1表示最后一位，默认-1
     * @param bool $desc       排序，false默认升序，true为倒序
     * @param bool $isGetScore true 获取成员与分数  false 获取成员
     *
     * @return array  返回有序集合中指定区间内的成员数组（默认返回所有）
     */
    public function get($start = 0, $stop = -1, $desc = false, $isGetScore = false)
    {
        $this->select();
        $key = $this->key;
        if ($desc === true) {
            if ($isGetScore == true) {
                return $this::$client->ZREVRANGE($key, $start, $stop, true);//倒序 key=>val
            }
            return $this::$client->ZREVRANGE($key, $start, $stop, 'WITHSCORES');//倒序 key 成员
        }
        if ($isGetScore == true) {
            return $this::$client->zrange($key, $start, $stop, true); //正序 key=>val
        }
        return $this::$client->zrange($key, $start, $stop, 'WITHSCORES'); //正序 key 成员
    }

    /**
     * 获取置顶范围-一个
     *
     * @param int $start
     * @param int $stop
     *
     * @return array
     */
    public function RangeByScoreGetOne($start = 0, $stop = 0, $limit = [])
    {
        $this->select();
        $key = $this->key;
        //return $this::$client->zRangeByScore($key, $start, $stop, ['withscores'=>false]);
        return $this::$client->zRangeByScore($key, $start, $stop, ['limit' => [0, 1]]);
    }

    /**
     * 分页获取数据
     *
     * @param        $current_page
     * @param        $per_page
     * @param string $sort
     *
     * @return array
     */
    public function getSortedSetList($current_page, $per_page, $sort = 'DESC')
    {
        $start = ($current_page - 1) * $per_page;
        if($per_page == 1){
            $stop  = $per_page;
        }else{
            $stop  = $start + ($per_page - 1);
        }
        $this->select();
        $key   = $this->key;
        $limit = [$start, $stop];
        if ($sort == 'DESC') {
            return $this::$client->zRevRangeByScore($key, '+inf', '-inf', ['limit' => $limit]);
        } else {
            return $this::$client->zRangeByScore($key, '-inf', '+inf', ['WITHSCORES' => true, 'limit' => $limit]);
        }
    }

    /**
     * 分页获取集合(降序)
     *
     * @param int $start
     * @param int $stop
     *
     * @return array
     */
    public function zRevRangeByScore($limit = [],$type = false)
    {
        $this->select();
        $key = $this->key;
        if($type){
            return $this::$client->zRevRangeByScore($key, '+inf', '-inf', ['WITHSCORES' => true,'limit' => $limit]);

        }
        return $this::$client->zRevRangeByScore($key, '+inf', '-inf', ['limit' => $limit]);
    }

    /**
     * 分页获取集合-有开始和结束范围(降序)
     *
     * @param int $start
     * @param int $stop
     *
     * @return array
     */
    public function zRevRangeByScoreNew($limit = [], $start = "-inf", $stop = "+inf",$type = false)
    {
        $this->select();
        $key = $this->key;
        if($type){
            return $this::$client->zRevRangeByScore($key, $start, $stop, ['WITHSCORES' => true,'limit' => $limit]);
        }
        return $this::$client->zRevRangeByScore($key, $start, $stop, ['limit' => $limit]);
    }


    /**
     * 分页获取集合(升序)
     *
     * @param int $start
     * @param int $stop
     *
     * @return array
     */
    public function zRangeByScore($limit, $start = "-inf", $stop = "+inf")
    {
        $this->select();
        $key = $this->key;
        return $this::$client->zRangeByScore($key, $start, $stop, ['WITHSCORES' => true, 'limit' => $limit]);
    }

    /**
     * 获取指定分数范围的成员数
     * @param $start >
     * @param $stop <=
     *
     * @return int
     */
    public function zCountByScore($start, $stop)
    {
        $this->select();
        $key = $this->key;
        return $this::$client->zCount($key, $start, $stop);
    }

    /**
     * 获取指定成员的排名
     * @param $member
     *
     * @return bool|int
     */
    public function zrevrank($member){
        $this->select();
        $key = $this->key;
        return $this::$client->zrevrank($key,$member);
    }

    /**
     * 获取置顶范围-全部
     *
     * @param int $start
     * @param int $stop
     *
     * @return array
     * @author chenpeng
     */
    public function RangeByScoreGetAll($start = 0, $stop = 0)
    {
        $this->select();
        $key = $this->key;
        return $this::$client->zRangeByScore($key, $start, $stop);

    }

    public function len($key = ''): int
    {
        $this->select();

        if (empty($key)) {
            $key = $this->key;
        }
        return $this::$client->zcard($key);
    }

    /**
     * @param string $member
     *
     * @return bool|int
     */
    public function getRanking(string $member)
    {
        $this->select();

        if (empty($key)) {
            $key = $this->key;
        }
        return $this::$client->zRevRank($key, $member);
    }

    /**
     * Set成员是否存在
     *
     * @param string $member
     *
     * @return bool
     */
    public function checkExists(string $member)
    {
        $this->select();
        $ret = $this::$client->zScore($this->key, $member);
        return false === $ret ? false : true;
    }

    /**
     * 获取指定分数之间的成员
     * 倒叙
     * @param $min
     * @param $max
     * @param $limit
     *
     * @return array
     */
    public function zRevRangeByScore_($min,$max,$limit)
    {
        $this->select();
        $key = $this->key;
        return $this::$client->zRevRangeByScore($key,$max,$min, ['limit' => $limit]);
    }
    /**
     * 获取指定分数之间的成员
     * 正序
     * @param $min
     * @param $max
     * @param $limit
     *
     * @return array
     */
    public function zRangeByScore_($min,$max,$limit)
    {
        $this->select();
        $key = $this->key;
        return $this::$client->zRangeByScore($key,$min,$max, ['limit' => $limit]);
    }
    /**
     * 返回有序集中，成员的分数值。
     *
     * @param string $member 成员
     *
     * @return float|bool   返回分数值(浮点型)，如果成员不存在返回false
     */
    public function zScore($member)
    {
        $this->select();
        return $this::$client->zscore($this->key, $member);
    }

    /**
     * 对有序集合中指定成员的分数加上增量
     *
     * @param string $member 指定元素
     * @param int    $num    增量值，负数表示进行减法运算，默认1
     *
     * @return float  返回运算后的分数值（浮点型）
     */
    public function zinc($member, $num = 1)
    {
        $this->select();
        return $this::$client->zincrby($this->key, $num, $member);
    }

    /**
     * 移除有序集中的一个或多个成员，不存在的成员将被忽略。
     *
     * @param string|array $members 要移除的成员，如果要移除多个请传入多个成员的数组
     *
     * @return int   返回被移除的成员数量，不存在的成员将被忽略
     */
    public function zrem($members)
    {
        $this->select();
        $num = 0;
        if (is_array($members)) {
            foreach ($members as $value) {
                $num += $this::$client->zrem($this->key, $value);
            }
        } else {
            $num += $this::$client->zrem($this->key, $members);
        }
        return $num;
    }

    /**
     * 删除指定集合
     *
     * @return false|int
     */
    public function zUnlink(){
        $this->select();
        if (!$this->key){
            return false;
        }
        if (!$this::$client->exists($this->key)){
            return false;
        }
        return $this::$client->unlink($this->key);
    }

    public function zGeo( $lng, $lat, $distance,$count,$sort){
        $this->select();
        return $this::$client->georadius($this->key, $lng, $lat, $distance, 'km', ['count'=>$count,$sort]);
    }

    public function zGeoAdd( $lng, $lat, $member){
        $this->select();
        return $this::$client->geoAdd($this->key, $lng, $lat,$member);
    }

}
